//Given an integer array nums, return the length of the longest strictly 
//increasing subsequence. 
//
// A subsequence is a sequence that can be derived from an array by deleting 
//some or no elements without changing the order of the remaining elements. For 
//example, [3,6,2,7] is a subsequence of the array [0,3,1,6,2,2,7]. 
//
// 
// Example 1: 
//
// 
//Input: nums = [10,9,2,5,3,7,101,18]
//Output: 4
//Explanation: The longest increasing subsequence is [2,3,7,101], therefore the 
//length is 4.
// 
//
// Example 2: 
//
// 
//Input: nums = [0,1,0,3,2,3]
//Output: 4
// 
//
// Example 3: 
//
// 
//Input: nums = [7,7,7,7,7,7,7]
//Output: 1
// 
//
// 
// Constraints: 
//
// 
// 1 <= nums.length <= 2500 
// -10⁴ <= nums[i] <= 10⁴ 
// 
//
// 
// Follow up: Can you come up with an algorithm that runs in O(n log(n)) time 
//complexity? 
// Related Topics 数组 二分查找 动态规划 👍 2021 👎 0

package leetcode.editor.cn;

import org.junit.Assert;

public class P300LongestIncreasingSubsequence {
    public static void main(String[] args) {
        Solution solution = new P300LongestIncreasingSubsequence().new Solution();
        Assert.assertEquals(solution.lengthOfLIS(new int[]{4, 10, 4, 3, 8, 9}), 3);
    }

    //leetcode submit region begin(Prohibit modification and deletion)
    class Solution {
        public int lengthOfLIS(int[] nums) {
            int len = nums.length;
            int[] pile = new int[len];
            pile[0] = nums[0];
            int m = 1;
            for (int i = 1; i < len; i++) {
                int cur = nums[i];
                int pre = pile[m - 1];
                if (cur > pre) {
                    pile[m++] = cur;
                } else {
                    //替换
//                    int j = 0;
//                    while (j < m - 1 && pile[j] < cur) {
//                        j++;
//                    }
//                    pile[j] = cur;
                    //通过二分替换
                    int left = 0;
                    int right = m - 1;
                    while (left <= right) {
                        int mid = (right + left) >> 1;
                        if (pile[mid] < cur) {
                            left++;
                        } else {
                            right--;
                        }
                    }
                    pile[left] = cur;
                }
            }
            return m;
        }
    }
//leetcode submit region end(Prohibit modification and deletion)

}